// Notation of position:
// ====================
// Height/Width (H/W) Head/Tail (H/T) [Radius (R)]
// 
//            HH/WHR                HH/WTR
// HH/WH   +----------------------------+ HH/WT
// TL      | /                        \ | 
// HHR/WH  |/                          \| HHR/WT
//         |                            |
//         |                            |
//         |                            |
//         |                            |
//         |                            |
//         |                            |
// HTR/WH  |\                          /| HTR/WT
//         | \                        / |
// HT/WH   +----------------------------+ HT/WT
//            HT/WHR                HT/WTR
// 

// Control Point Adjusting:
// 
// Adjust the "sharpness" of the rounded corner by creating overhead of control points

const control = (x, y, inc, dir) => {
  const [w1,    h1,   w2,   h2] = {
    TL: [0,   -inc, -inc,    0],
    TR: [inc,    0,    0, -inc],
    BR: [0,    inc, inc,     0],
    BL: [-inc,   0,    0,  inc]
  }[dir];
  return `${x + w1} ${y + h1} ${x + w2} ${y + h2}`
}
  
const curveTo =(dir, type, cornerW, cornerH, radW, radH, inc) => {
  return type === 'C'
  ? `C ${control(cornerW, cornerH, inc, dir)} ${ radW } ${ radH }`
  : `L ${ cornerW } ${ cornerH } L ${ radW } ${ radH  }`
}

const cuboxPath = (size, radius, rawStrokeWidth=0, initCorners={}) => {

  const {height: h, width: w} = size;
  
  const {max, min} = Math;
    
  // N.B:
  // 
  // (tl;dr) DO NOT MESS UP WITH THE MAGIC NUMBERS BELOW. 
  // 
  // You should be aware of the difference of corner curvature on the stroke
  // of the box. It's been proven that you cannot calculate the "edge" of a
  // bezier stroke with merely the curve equation and a "width". The edge of
  // a cubic bezier stroke is not cubic anymore -- it's actually a 10-order
  // curve, and can only be approximated.
  // 
  // Pomax provides extensive material about Bezier curve. Worth reading.
  // https://pomax.github.io/bezierinfo/
  // 
  // What I did here is a very naive approach. The box should behave same as
  // the CSS property "box-sizing: border-box", i.e. the border is part of
  // the box when calculating box size. Thus the property "cornerRadius" of
  // the box are always about the outer edge of the stroke.
  // 
  // Conceivably the corner curvature of the inner edge of the stroke gets
  // greater (the corner gets sharper), and this is an empirical estimation
  // of the relationship between the sharpness of inner corner curvature and
  // the stroke width.
  // 
  // In very rare cases, you would draw some blocks with this component, and
  // you will probably draw stroke with width larger than a pixel. In most
  // cases, you don't. The parameters below works perfectly for pixel-width
  // stroke. So no need to change them. If you find that the stroke width looks
  // unevenly,  especially for the thick stroke, it would be better for you
  // to draw your own SVG.  

  const radi = max(min(radius, min(w, h) / 2), 15);  
    const HHR = radi;
    const WHR = radi;
    const HTR = h - HHR;
    const WTR = w - WHR;

  const off = min(radi, rawStrokeWidth);
    const HH = off;
    const WH = off;
    const HT = h - HH;
    const WT = w - WH;

    const inc = min( radi / off , off) / 2;

  const corners = {TL:'C', TR:'C', BR:'C', BL:'C', ...initCorners};

  return `M ${WH} ${HHR}
    ${curveTo('TL', corners['TL'], WH, HH, WHR, HH , inc, )} L ${ WTR } ${ HH  }
    ${curveTo('TR', corners['TR'], WT, HH, WT,  HHR, inc, )} L ${ WT  } ${ HTR }
    ${curveTo('BR', corners['BR'], WT, HT, WTR, HT , inc, )} L ${ WHR } ${ HT  }
    ${curveTo('BL', corners['BL'], WH, HT, WH,  HTR, inc, )} L ${ WH  } ${ HHR }`
}

export default cuboxPath;